package com.mp.approvalreq.servlet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.entity.Query;
import com.mp.approvalreq.entity.Request;
import com.mp.approvalreq.entity.adjust.VersionInfo;
import com.mp.approvalreq.util.EmailUtils;
import com.mp.user.entity.User;
import com.plusmoney.exception.ExceptionMessage;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class AbstractServlet extends HttpServlet {

    private static final long serialVersionUID = 7604097086911358035L;

    private static final Logger logger = LoggerFactory.getLogger(AbstractServlet.class);

    protected User getReqUser(HttpServletRequest request) {
        return (User) request.getAttribute("user");
    }

    /**
     * 客户端 输入流---> 字符串
     *
     * @return
     * @throws IOException
     */
    protected String getContent(HttpServletRequest req) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream(), StandardCharsets.UTF_8));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        if ("".equals(sb.toString().trim())) {
            if (req.getAttribute("reqBody") != null) {
                return String.valueOf(req.getAttribute("reqBody"));
            } else {
                return sb.toString();
            }
        } else {
            req.setAttribute("reqBody", sb.toString());
            return sb.toString();
        }
    }

    protected void printJson(HttpServletResponse resp, String jsonStr) throws IOException {
        resp.setHeader("Content-Type", "application/json;charset = utf-8");
        resp.setCharacterEncoding("UTF-8");

        resp.getWriter().write(jsonStr);
        resp.flushBuffer();
        resp.getWriter().close();
    }


    Integer getUserGeneration(HttpServletRequest req) {
        String userGeneration = req.getParameter("generation");
        return userGeneration == null ? 0 : Integer.parseInt(userGeneration);
    }

    /**
     * 获取平台客户端输入的参数
     *
     * @param request
     * @return
     * @throws Throwable
     */
    protected String parametersReq(HttpServletRequest request) throws Throwable {
        StringBuilder builder = new StringBuilder(request.getRequestURL());
        builder.append(" ").append(request.getMethod()).append(" ");

        if ("GET".equals(request.getMethod()) || "POST".equals(request.getMethod())) {
            for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
                for (String s : entry.getValue()) {
                    builder.append(entry.getKey()).append("=").append(s).append("&");
                }
            }
        }
        logger.info("interface: " + builder.toString());
        return builder.toString();
    }


    private void printThrowable(HttpServletRequest req, HttpServletResponse response, Throwable throwable) throws ServletException, IOException {
        String[] url = req.getRequestURL().toString().split("/");
        String interfaceName = url[url.length - 1];

        try {
            if ("addComment".equalsIgnoreCase(interfaceName)) {
                JSONObject jo = JSONObject.parseObject(throwable.getMessage());
                jo.put("respCode", "10003");
                jo.put("respDesc", jo.getString("res_info"));
                response.getWriter().write(jo.toJSONString());
            } else {
                response.getWriter().write(throwable.getMessage());
            }
            response.getWriter().flush();
            response.getWriter().close();
        } catch (Exception e) {
            JSONObject jo = new JSONObject();
            jo.put("result", 10000);
            jo.put("res_info", "系统繁忙,请稍候再试");
            jo.put("erpCode", 10000);
            jo.put("erpMsg", "系统繁忙,请稍候再试");
            logger.info(jo.toJSONString());
            response.getWriter().write(jo.toJSONString());
            response.getWriter().flush();
            response.getWriter().close();
        }
    }

    /**
     * 往客户端输出错误提示
     *
     * @param req
     * @param response
     * @param throwable
     * @throws ServletException
     * @throws IOException
     */
    protected void onThrowable(HttpServletRequest req, HttpServletResponse response, Throwable throwable) throws ServletException, IOException {
        logger.error(throwable.getMessage(), throwable);
        response.setHeader("Content-Type", "application/json;charset = utf-8");
        response.setCharacterEncoding("UTF-8");

        try {
            if (throwable.getMessage().contains("DATABASE_ERROR") ||
                    throwable.getMessage().contains("SYSTEM_ERROR")) {
                String errorInfo = getErrorInfo(req, throwable);
                logger.error(errorInfo);
                EmailUtils.sendMail("审批系统出错", errorInfo);
            }
        } catch (Throwable e) {
            logger.info(e.getMessage(), e);
        }

        if (throwable instanceof RpcServerLogicalException) {
            try {
                ExceptionMessage em = JSON.parseObject(throwable.getMessage(), ExceptionMessage.class);
                if (StringUtils.isNotEmpty(em.getRespCode()) && "002".equals(em.getRespCode())) {
                    JSONObject jsonStr = new JSONObject();
                    jsonStr.put("erpCode", "002");
                    jsonStr.put("erpMsg", "提交成功");

                    response.getWriter().write(jsonStr.toJSONString());
                    response.getWriter().flush();
                    response.getWriter().close();
                } else {
                    printThrowable(req, response, throwable);
                }
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
                printThrowable(req, response, throwable);
            }
        } else {
            printThrowable(req, response, throwable);
        }
    }

    String getErrorInfo(HttpServletRequest req, Throwable throwable) {
        StrBuilder sb = new StrBuilder();
        try {
            sb.append("请求URL:").append(parametersReq(req));
            sb.append("\n");
            sb.append("请求参数:").append(getContent(req));
            sb.append("\n");
            sb.append("错误信息:").append(JSONObject.toJSONString(throwable));
            sb.append("\n");
            sb.append("用户信息:").append(JSONObject.toJSONString(getReqUser(req)));
            sb.append("\n");
            sb.append("版本信息:").append(JSONObject.toJSONString(getVersionInfo(req)));
            sb.append("\n");
            sb.append("header:").append(getHeaderInfo(req));
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
        return sb.toString();
    }

    private String getHeaderInfo(HttpServletRequest req) {
        Enumeration<String> headerNames = req.getHeaderNames();
        Map<String, String> map = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            map.put(name, req.getHeader(name));
        }
        return JSONObject.toJSONString(map);
    }

    /**
     * url decode
     *
     * @param str
     * @return
     * @throws Exception
     */
    protected String urlDecoder(String str) throws Exception {
        if (StringUtils.isNotEmpty(str)) {
            return URLDecoder.decode(str, "UTF-8");
        }
        return null;
    }

    /**
     * url encode
     *
     * @param str
     * @return
     * @throws Exception
     */
    protected String urlEncoder(String str) throws Exception {
        if (StringUtils.isNotEmpty(str)) {
            return URLEncoder.encode(str, "UTF-8");
        }
        return null;
    }


    Query getQuery(HttpServletRequest req, User user, Request request) {
        Query query = new Query(user);
        query.setRequestId(request.getRequestDkey());
        query.setApplicant(request.getApplicant());
        query.setOrderBy(request.getOrderBy());
        query.setDataNum(request.getDataNum());
        query.setPage(request.getPage());
        mergeStatus(request, query);
        query.setFinancialStatusSequence(request.getFinancialStatusSequence());
        VersionInfo versionInfo = getVersionInfo(req);
        query.setVersionInfo(versionInfo);
        if (Utils.isNotNull(request.getGeneration())) {
            query.setGeneration(request.getGeneration());
        }
        return query;
    }


    private void mergeStatus(Request request, Query query) {
        if (StringUtils.isBlank(request.getFinishedSequence())) {
            query.setFinishedSequence(request.getCurrentStatus());
            return;
        }
        if (StringUtils.isBlank(request.getCurrentStatus())) {
            query.setFinishedSequence(request.getFinishedSequence());
            return;
        }
        Set<Integer> set = new TreeSet<>();
        set.addAll(Utils.string2list(request.getCurrentStatus()));
        set.addAll(Utils.string2list(request.getFinishedSequence()));
        query.setFinishedSequence(Utils.collection2string(set));
    }

    void printSuccessJson(HttpServletResponse resp) throws IOException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("result", "0");
        jsonObject.put("res_info", "操作成功");

        logger.info(jsonObject.toJSONString());

        printJson(resp, jsonObject.toJSONString());
    }

    VersionInfo getVersionInfo(HttpServletRequest req) {
        try {
            Enumeration<String> headerNames = req.getHeaderNames();
            VersionInfo versionInfo = new VersionInfo();
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String header = req.getHeader(name);

                switch (name) {
                    case "platform":
                    case "appplatform":
                        versionInfo.setPlatform(header.toLowerCase());
                        break;
                    case "appversion":
                        String[] data = header.split(" ");
                        versionInfo.setVersionType(data[0].toLowerCase());
                        versionInfo.setVersionNum(data[1]);
                        break;
                    case "platformversion":
                        String[] list = header.split("-");
                        versionInfo.setVersionType(list[0] + "-" + list[1]);
                        versionInfo.setVersionNum(list[2].replaceAll("-", ""));
                        break;
                }
            }
            logger.info("versionInfo:{}", JSONObject.toJSONString(versionInfo));
            return versionInfo;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }
    protected void remindUpdate(HttpServletResponse response) throws IOException {
        JSONObject jo = new JSONObject();
        jo.put("result", 10000);
        jo.put("res_info", "请更新大管加版本");
        jo.put("erpCode", 10000);
        jo.put("erpMsg", "请更新大管加版本");
        logger.info(jo.toJSONString());
        response.getWriter().write(jo.toJSONString());
        response.getWriter().flush();
        response.getWriter().close();
    }

}